/**
 * video工具类
 * @author savage
 * @version 1.0.2
 * @update 2017-02-10 13:53:46
 */


(function (root, factory) {
  if (typeof define === 'function' && define.amd) {
    // AMD
    define(['jquery'], factory);
  } else if (typeof exports === 'object') {
    // Node, CommonJS之类的
    module.exports = factory(require('jquery'));
  } else {
    // 浏览器全局变量(root 即 window)
    root.scooper = root.scooper || {};

    root.scooper.video = factory(root.jQuery);
  }
}(this, function ($) {
  "use strict";

  window.console = window.console || (function () {
    var c = {};
    c.log = c.warn = c.debug = c.info = c.error = c.time = c.dir = c.profile = c.clear = c.exception = c.trace = c.assert = function () {};
    return c;
  })();

  /**
   * 立即执行函数形式
   * 兼容IE8 indexOf
   */
  (function () {
    if (Array.prototype.indexOf) {
      return;
    }
    Array.prototype.indexOf = function (item) {
      var len = this.length >>> 0; //保证结构为非负数

      for (var i = 0; i < len; i++) {
        if (i in this && this[i] === item) {
          return i;
        }
      }
      return -1;
    }
  })();

  /**
   * 闭包
   * 为事件添加唯一标识字符串
   */
  var guid = (function () {
    var id = 1;
    return function () {
      return 'SCVIDEO_ID_' + (++id).toString();
    }
  })();

  /**
   * 公共方法
   * 判断是否为IE
   */
  function isIE() {
    return !!window.ActiveXObject || "ActiveXObject" in window;
  }

  /**
   * 克隆对象
   * 让新出来的对象是独立的
   */
  function cloneObj(obj) {
    var str, newObj = $.isArray(obj) ? [] : {};
    if (typeof obj != 'object') {
      return;
    }

    if (window.JSON) {
      str = JSON.stringify(obj);
      newObj = JSON.parse(str);
    } else {
      $.each(obj, function (key, val) {
        newObj[key] = typeof val == 'object' ? cloneObj(val) : val;
      });
    }
    return newObj;
  }

  /**
   * 公共方法
   * 提示
   */
  function promptSuccess(msg, type) {
    // console.log(msg);
    //panduanpromptView弹层对象是否引入
    "undefined" != typeof (promptView) && promptView.showSuccess(msg);
  }

  function promptFailed(msg, type) {
    console.error(msg);
    "undefined" != typeof (promptView) && promptView.showFailed(msg);
  }

  function promptAlarm(msg, type) {
    console.info(msg);
    "undefined" != typeof (promptView) && promptView.showAlarm(msg);
  }

  /**
   * 公共方法
   * 判断是否是安全连接
   */
  function checkIsHttp() {
    var protocolStr = document.location.protocol;
    if (protocolStr == "http:" /*&& window.location.hostname != "localhost"*/ ) return true;
    return false;
  }

  /**
   * 事件对象包装类，通过事件type，加载必要的属性
   *  @class
   */
  function VideoEvent(type, target) {
    this.type = type;
    this.returnValue = true;
    this.target = target || null;
    this.currentTarget = null;
  }

  /**
   * 轮巡工具类
   */
  var PollTimer = /** @class */ (function () {
    function PollTimer(cb, time) {
      cb(true); // 首次执行
      this.timerId = setInterval(cb, time * 1000);
    }
    PollTimer.prototype.stop = function () {
      if (!this.timerId)
        return;
      clearInterval(this.timerId);
      this.timerId = 0;
    };
    return PollTimer;
  }());

  //事件
  function Listener() {
    // 在构造函数中进行初始化
    this._listeners = {};
  }

  Listener.prototype = {

    constructor: Listener,
    /**
     * 添加事件
     */
    addListener: function (type, handler, key) {
      if (typeof handler != 'function') {
        return;
      }
      var t = this._listeners,
        id;
      if (typeof key == "string" && key) {
        if (/[^\w\-]/.test(key)) {
          throw ("nonstandard key:" + key);
        } else {
          handler.hashCode = key;
          id = key;
        }
      }
      type.indexOf("on") != 0 && (type = "on" + type);
      typeof t[type] != "object" && (t[type] = {});
      id = id || guid();
      handler.hashCode = id;
      t[type][id] = handler;
    },

    /**
     * 删除事件
     */
    removeListener: function (type, handler) {
      type.indexOf("on") != 0 && (type = "on" + type);
      var t = this._listeners;
      if (!t[type]) {
        return;
      }
      if (handler) {
        if (typeof handler == 'function') {
          handler = handler.hashCode;
        } else if (typeof key != "string") {
          return;
        }
        t[type][handler] && delete t[type][handler];
      } else {
        t[type] = {};
      }
    },
    /**
     * 派发事件
     */
    dispatch: function (e, options) {
      if (typeof e == 'string') {
        e = new VideoEvent(e);
      }
      options = options || {};
      for (var i in options) {
        e[i] = options[i];
      }
      var i, t = this._listeners,
        p = e.type;
      e.target || (e.target = this);
      e.currentTarget = this;
      p.indexOf("on") != 0 && (p = "on" + p);
      typeof this[p] == 'function' && this[p].apply(this, arguments);
      if (typeof t[p] == "object") {
        for (i in t[p]) {
          t[p][i].call(this, e);
        }
      }
      return e.returnValue;
    }
  }

  var videoListener = new Listener();

  /**
   * 使用ocx方式的video工具类
   * @author savage
   * @version 1.0.0
   */
  function VideoOcx($dom, opts) {
    if (!isIE()) {
      console.log('视频控件不支持非IE浏览器');
      return this._getTipObj();
    }
    if (!opts) {
      console.error('VideoOcx的参数opts不能为空');
      return;
    }
    this._init($dom, opts);
  }

  /**
   * 使用ocx方式的视频播放的方法
   */
  VideoOcx.prototype = {

    constructor: VideoOcx,
    /**
     * 播放视频
     * 参数：index(视频窗口编号，从0开始) video(视频设备id，即devId) id(标识，空的话使用设备id) opts(其他参数)
     * 返回true/false
     */
    play: function (index, video, id, opts) {
      /*if (!$.isNumeric(video*1)) {
      	throw new Error('video is not number,id = '+id);
      }*/
      // console.log("play >>> " + "video=" + video + "; id=" + id + "; index=" + index);
      this.dispatch('beforeplay', {
        index: index,
        video: video,
        id: id
      });

      this._obj.SCWebSetCurrentWindow(index);
      var playId = this._obj.SCWebRealPlay(video, this._opts.streamType);
      console.log("play = " + playId);

      opts = opts || {};
      playId > 0 && (this.videoStatus[index] = {
        video: video,
        id: id,
        playId: playId,
        opts: opts
      }, this.dispatch('playsuccess', this.videoStatus[index]));

      if (playId < 0) {
        var name = opts.name || '视频';
        promptFailed(name + '播放失败！');
      }

      return playId > 0;
    },

    /**
     * 在序号最小的空闲窗口播放视频
     * 参数：index(视频窗口编号，从0开始) video(视频设备id，即devId) opts(其他参数)
     * 返回true/false
     */
    playByOrder: function (video, id, opts) {
      var freeWindow = this._getMinIndexFreeWindow(0);

      if (freeWindow == -1) {
        return this.playInChoice(video, id, opts);
      }
      return this.play(freeWindow, video, id, opts);
    },

    /**
     * 扩展视频窗口数的播放方式
     */
    playByOrderExpandWindow: function (video, id, opts) {

      var freeWindow = this._getMinIndexFreeWindow(0);

      while (this._opts.windows < 16 && freeWindow == -1) {
        var zoom = Math.sqrt(this._opts.windows * 1) + 1;

        if (this._opts.windows == 6) {
          this.setWindowsNum(9);
        } else {
          this.setWindowsNum(Math.pow(zoom, 2));
        }

        freeWindow = this._getMinIndexFreeWindow(zoom - 1);
      }

      if (freeWindow == -1 ||
        (this._getChoiceWindow() != -1 && !this.getInChoiceVideo())) {
        return this.playInChoice(video, id, opts);
      }
      return this.play(freeWindow, video, id, opts);
    },

    /**
     * 播放所有视频
     */
    playAll: function (array) {
      if (array.length > this._opts.windows) {
        throw new Error('windows is not enough');
      }
      var me = this;
      me.closeAll();
      $.each(array, function (i, obj) {
        me.play(i, obj.video, obj.id, obj.opts);
      });
    },
    /**
     * 在鼠标选中的窗口中播放视频
     */
    playInChoice: function (video, id, opts) {
      var index = this._obj.SCWebGetCurrentWindowIndex();
      this.videoStatus[index] && this.close(index);
      return this.play(index, video, id, opts);
    },
    /**
     * 如果被指定的窗口有视频id，则播放
     */
    playMulWindows: function (indexs) {
      var me = this;
      $.each(indexs, function (i, index) {
        me.videoStatus[index] && me.play(index, me.videoStatus[index].video, me.videoStatus[index].id);
      });
    },
    /** 
     * 检索当前点的视频是否被播放，被播放则返回播放的视频窗口
     */
    isPlaying: function (id) {
      var index = -1;
      $.each(this.videoStatus, function (key, val) {
        if (id == val.id) {
          index = key;
          return false;
        }
      });
      return index;
    },

    /**
     * 关闭语音
     * @param window
     */
    closeVoice: function (window) {

      this._obj.CWebVoiceComControl(window, 0);
    },

    getWindowByPlayId: function (playId) {
      var index = -1;
      $.each(this.videoStatus, function (key, val) {
        if (playId == val.playId) {
          index = key;
          return false;
        }
      });
      return index;
    },

    getPlayIdBywindow: function (index) {
      return this.videoStatus[index].playId;
    },

    /**
     * 关闭指定窗口的视频
     */
    close: function (index, isSave) {

      if (!this.videoStatus[index] || index >= this._opts.windows || this._disableClosed.indexOf(index * 1) > -1) {
        return;
      }
      this._obj.SCWebSetCurrentWindow(index);
      var close = this._obj.SCWebStopRealPlay(this.videoStatus[index].playId);
      console.log("close = " + close);

      if (!isSave) {
        this.dispatch('afterclose', this.videoStatus[index]);
        delete this.videoStatus[index];
      }

    },

    /**
     * 
     */
    closeHistory: function (playId) {
      var close = this._obj.SCWebStopRealPlay(playId);
      console.log("close = " + close);
    },

    /**
     * 关闭所有视频
     * TODO 不可关闭
     */
    closeAll: function (isSave) {
      var me = this;
      isSave || (this._disableClosed = []);
      var windows = me._obj.SCWebGetRealPlayWindows();
      if (windows) {
        $.each(windows.split(','), function (i, index) {
          me.close(index, isSave);
        });
      }
    },

    /**
     * 获取视频窗口
     * @returns
     */
    getWindowsPlay: function () {
      var me = this;
      var windows = me._obj.SCWebGetRealPlayWindows();
      return windows;
    },

    /**
     * 设置鼠标选中窗口
     */
    setChoiceWindow: function (index) {
      this._obj.SCWebSetCurrentWindow(index);
    },
    /**
     * 获取视频窗口数
     */
    getWindowsNum: function () {
      return this._opts.windows;
    },
    /**
     * 是否还有空闲窗口
     */
    hasFreeWindow: function () {
      return this._obj.SCWebGetFreeWindows() != '';
    },

    /**
     * 设置视频窗口数
     */
    setWindowsNum: function (num, extra) {
      var me = this;
      num = num * 1;
      var result;
      if (extra) {
        result = me._obj.SCWebDecoderSetExtraScreenMode(num);
      } else {
        result = me._obj.SCWebDecoderSetScreenMode(num);
      }
      console.log("setWindowsNum >>> " + "result=" + result);
      /*extra
      ? me._obj.SCWebDecoderSetExtraScreenMode(num)
      : me._obj.SCWebDecoderSetScreenMode(num);*/
      num = num == 66 ? 6 : num;
      me._changeWindowsAction(num);
      me.dispatch('screenchange', {
        windowNums: num
      });
      me._opts.windows = num;
      me._opts.extra = extra;

    },

    /**
     * 询问是否无可用窗口
     */
    isUnavailable: function () {
      return this._opts.windows == 16 && !this.hasFreeWindow();
    },

    disableClosed: function (num) {
      $.isNumeric(num) ? this._disableClosed.push(num) :
        $.isArray(num) && (this._disableClosed = this._disableClosed.concat(num));

    },

    enableClosed: function () {
      this._disableClosed = [];
    },

    //轮巡就是建立一个轮巡数组，然后根据最大屏幕数去遍历数组，记录当前轮巡下标，并标记该视频已被打开，如果视频关闭后 将视频标记为未关闭，建立一个定时器反复去执行这些动作。
    //如果要执行之前视频的记录保存，那么关闭轮巡的关闭方法就需要重新写，或者关闭的时候加一个参数去判断。

    //云台就是调用 dataHolder方法
    /**
     * 执行轮巡
     */
    startPoll: function (array, time) {
      if (!array || array.length == 0) {
        promptAlarm('请选择视频设备！');
        return false;
      }

      time = $.isNumeric(time) ? time : this._opts.pollInterval;
      this._pollArray = array;
      var me = this,
        windowNum = me._opts.windows,
        maxNum = array.length,
        nowNum = 0;
      me.saveList();

      this._polltimer = new PollTimer(function (firstRun) {
        me.closeAll();
        for (var i = 0; i < windowNum; i++) {
          if (nowNum == maxNum) {
            nowNum = 0;
            if (maxNum < windowNum) {
              break;
            }
          }

          me.playByOrder(array[nowNum].video, array[nowNum].id, array[nowNum].opts);
          nowNum++;
        }
        if (firstRun) {
          me.dispatch('startpoll', array);
        }
      }, time);
    },

    /**
     * 结束轮巡
     */
    stopPoll: function () {
      if (!this._polltimer) {
        return;
      }
      this._polltimer.stop();
      this._polltimer = undefined;
      console.log('------> 轮巡结束 <-------');
      this.dispatch('stoppoll', {});
      //恢复之前打开的视频
      this.playSaveList();
    },

    /**
     * 获取是否在轮巡
     */
    isPolling: function () {
      return !!this._polltimer;
    },

    /**
     * 云台控制
     * up  				上
     * down				下
     * left				左
     * right			右
     * upleft			上左
     * upright			上右
     * downleft			下左
     * downright		下右
     * zoomin			倍率变大
     * zoomout			倍率变下
     * focusnear		焦点+
     * focusfar			焦点-
     * irisopen			光圈+
     * irisclose		光圈-
     * pointset			设置预置点
     * pointdel			删除预置点
     * pointgoto		到预置点
     * scansetleft		自动扫描左边界
     * scansetright		自动扫描又边界
     * scansetspeed		设置扫描速度
     * scanrun			自动扫描运行
     * cruiseadd		添加巡航点
     * cruisedel		删除巡航点
     * cruisespeed		设置巡航点速度
     * cruisepausetime	设置巡航滞留时间
     * cruiserun		启动巡航
     */
    holder: function (type, opts, isStop) {
      var index = this._getChoiceWindow();
      if (!this.videoStatus[index]) {
        promptAlarm('未选中播放的视频！');
        return;
      }

      var holdType = 'up down left right upleft upright downleft downright zoomin zoomout focusnear focusfar irisopen irisclose pointset pointdel pointgoto ' +
        'scansetleft scansetright scansetspeed scanrun cruiseadd cruisedel cruisespeed cruisepausetime cruiserun';

      var typeVal = (Number(holdType.split(' ').indexOf(type)) + Number(1));
      console.log("holdType：" + typeVal + " type：" + type + (isStop ? ' 停止' : ''));

      if (!typeVal || typeVal <= 0) {
        console.error('异常PTZ指令：' + typeVal);
      }

      var video = this.videoStatus[index].video;

      if (isStop) {
        //var playerId = this._obj.SCWebGetCurrentPlayID();
        var result = this._obj.SCWebPTZControl(video, 1, typeVal, 0, 0, 0, 0);
        //var result = this._obj.SCWebPTZControlEx(playerId, 4, 1, 1);
        console.log(">>>>yuntai control,stop, video=" + video + ", result=" + result);
        return;
      }
      var _opts = {
        speed: 200,
        group: 0,
        present: 0,
        time: 0
      }
      $.extend(_opts, opts);
      this._obj.SCWebPTZControl(video, 0,
        typeVal, _opts.speed, _opts.group, _opts.present, _opts.time);
      console.log('设备号：' + video + ', 云台移动-->' + type);
    },

    /**
     * 视频回放
     * @param startTime [YYYY-MM-DDTHH:mm:ss]
     * @param endTime
     * @return playId
     */
    playHistory: function (video, startTime, endTime, opts) {
      return this._obj.SCWebHistoryPlay(video, startTime, endTime);
    },

    /**
     * 历史流控制
     * @param  {number} playId    
     * @param  {string} playType  播放类型（play && pause）
     * @param  {numner} playSpeed 播放速率
     * @param  {string} startTime 回放时间（暂时无用）
     */
    historyControl: function (playId, playType, playSpeed, startTime) {
      var contorlType = {
        play: 1,
        pause: 2
      };

      var playCommand = contorlType[playType];
      if (!playCommand) {
        console.error('unsupported type: ', playType);
        return;
      }

      this._obj.SCWebHistoryControl(playId, playCommand, playSpeed, startTime);
    },

    /**
     * 历史流控制（原）
     */
    _historyControl: function (playId, type, speed, startTime) {
      var contorlType = {
        normal: 1,
        pause: 2,
        'continue': 3,
      };
      var commad = 1;

      type == 'speed' ? speed && speed < 1 ? (commad = 7, speed = 1 / speed) : commad = 6 :
        commad = contorlType[type];

      this._obj.SCWebHistoryControl(playId, commad, speed);

    },

    /**
     * 跳转历史流
     */
    skipHistory: function (playId, time) {
      this._obj.SCWebHistorySeekPlay(playId, time);
    },

    /**
     * 抓图
     * @return 0:失败|1：成功
     */
    capturePicture: function (playId) {
      var videoCapImagePath = this._opts.videoCapImagePath ? this._opts.videoCapImagePath : '';
      return this._obj.SCWebCapturePicture(playId, videoCapImagePath, '');
    },


    saveList: function () {
      this._saveList = cloneObj(this.videoStatus);
    },

    playSaveList: function () {
      if (!this._saveList) {
        return;
      }
      this.closeAll();
      var me = this;
      $.each(this._saveList, function (index, obj) {
        me.play(index, obj.video, obj.id, obj.opts);
      });
    },

    /**
     * 获取当前选择窗口的视频video
     */
    getInChoiceVideo: function () {
      return this.videoStatus[this._obj.SCWebGetCurrentWindowIndex()];
    },

    /**
     * 获取当前选择的窗口的playId
     */
    getInChoicePlayId: function () {
      return this._obj.SCWebGetCurrentPlayID();
    },

    /**
     * 设置全屏
     */
    setFullScreen: function () {
      this._obj.ScWebFullScreen(1);
    },

    /**
     * 获取当前视频控件的配置项
     */
    getVideoControllerOpts: function () {
      return this._opts;
    },

    /**
     * 添加事件
     */
    addListener: function (type, handler, key) {
      videoListener.addListener(type, handler, key);
    },

    /**
     * 删除事件
     */
    removeListener: function (type, handler) {
      videoListener.removeListener(type, handler);
    },
    /**
     * 派发事件
     */
    dispatch: function (e, options) {
      videoListener.dispatch(e, options);
    },

    /*
	 * 总的初始化
	 * 参数示例：			
	 * var opts = {
				windows: 4,   //初始化的窗口数
				conf: {       //配置参数
					user: conf['video.username'],   //用户名
					passwd: conf['video.password'], //密码
					ip: conf['video.ip'],           //videoServer ip
					port: conf['video.port'],       //videoServer port
					token : token                   //通讯录令牌，若token非空，则用户名和密码可不传
				},
				extra: false,
				streamType: 0,                  //码流类型 默认0
				openChangeWindowStrategy: true, //打开策略，切屏:属性为true，则当从大分屏切换到小分屏的时候会保留被关闭的视频，如果未设置 则不保留
				capImage: true,                 //是否截屏:属性为true的时候，视频上会浮现控制条，进行截图、云台控制操作
				videoCapImagePath: conf['video.cap.image.path'] //截屏默认保存的地址
				pollInterval: 30                //轮巡时间，单位秒
		};
	 */
    _init: function ($dom, opts) {
      var me = this;
      //配置项
      me._opts = {
        windows: 4,
        conf: {},
        extra: false,
        ocxName: '__videoDiv',
        streamType: 0,
        openChangeWindowStrategy: false,
        capImage: false,
        videoCapImagePath: '',
        pollInterval: 10
      };

      $.extend(me._opts, opts);
      var windowsArr = me._opts.windowsArr;
      if (!windowsArr || windowsArr.length == 0) {
        me._windowList = {
          1: {},
          4: {},
          6: {},
          9: {},
          16: {}
        }
        me._windowsArr = [1, 4, 6, 9, 16];
      } else {
        me._windowList = {};
        for (var index in windowsArr) {
          var item = windowsArr[index];
          me._windowList[item] = {};
        }
        me._windowsArr = windowsArr;
      }

      //me._windowList = {1:{},2:{},3:{},4:{}}

      if (!$.isNumeric(me._opts.pollInterval)) {
        console.error('pollInterval should be number');
        return;
      }

      //事件注册区域
      me._addStopHandler();
      me._addClickHandler();
      me._addHishandler();

      //浏览器刷新/关闭前执行
      me._beforeUnload();

      //当前视频窗口的值
      me.videoStatus = {};
      //不可关闭的窗口
      me._disableClosed = new Array();
      //动态生成monitor对象
      me._obj = $('<OBJECT>').attr({
        id: me._opts.ocxName,
        name: me._opts.ocxName,
        classid: 'clsid:5D62BFBF-7B2D-4E9E-A359-5228400C77BC',
        width: '100%',
        height: '100%'
      });
      $dom.append(me._obj);

      me._obj = me._obj[0];


      var conf = me._opts.conf;
      //初始化和登录
      var init = me._obj.ScWebDecoderInit(0);
      console.log('init：' + init);
      //是否开启抓图


      var login;
      if (conf.token && conf.token.length > 0 && me._obj.SCWebDecoderLoginInVS_Token) {
        login = me._obj.SCWebDecoderLoginInVS_Token(conf.token, conf.ip, conf.port);
      } else {
        login = me._obj.SCWebDecoderLoginInVs(conf.user, conf.passwd, conf.ip, conf.port);
      }
      console.log('login：' + login);

      //调整分屏模式
      setTimeout(function () {
        //设置云台抓图控制按钮
        me._opts.capImage && me._obj.SCWebSetPtzButtonLayout('');

        me._opts.extra ?
          me._obj.SCWebDecoderSetExtraScreenMode(me._opts.windows) :
          me._obj.SCWebDecoderSetScreenMode(me._opts.windows);
      }, 100);

    },

    /**
     * TODO 添加注释
     */
    _getTipObj: function () {
      var obj = {};
      var fncName = 'play playByOrder playAll playInChoice playMulWindows click getWindowsNum setWindowsNum',
        fncName2 = 'isPlaying setChoiceWindow close closeAll enableClosede disableClosed addListener removeListener dispatch';
      $.each(fncName.split(' '), function (i, name) {
        obj[name] = function () {
          alert('不支持非IE环境');
        }
      });
      $.each(fncName2.split(' '), function (i, name) {
        obj[name] = function () {
          console.log('不支持非IE环境');
        }
      });
      obj.type = 'disable';
      return obj;
    },

    /**
     * 获取编号最小的空闲窗口的编号
     */
    _getMinIndexFreeWindow: function (searchedZoom) {
      searchedZoom = searchedZoom || 0;
      var index = Math.ceil(Math.pow(searchedZoom, 2));
      for (; index < this._opts.windows; index++) {
        if (this.videoStatus && this.videoStatus.length > 0) {

        } else {
          return;
        }
        if (!this.videoStatus[index]) {
          return index;
        }
      }
      return -1;
    },

    /**
     * 获取选择的窗口的编号
     */
    _getChoiceWindow: function () {
      //        	var playId = this._obj.SCWebGetCurrentPlayID();
      //        	var index;
      //        	if (playId > 0) {
      //        		index = this._obj.SCWebGetRealPlayWindows().split(',')[0];
      //        		this.setChoiceWindow(index ? index : 0);
      //        	}
      //        	return index;
      return this._obj.SCWebGetCurrentWindowIndex();
    },

    /**
     * 切换分屏
     */
    /*        _changeWindowsAction: function(num) {
    			var me = this,
    				old = me._opts.windows,
    				now = num,
    				oldZoom = Math.sqrt(old),
    				nowZoom = Math.sqrt(now);
    			if (old == now) {
    				return;
    			}
    			if (me._opts.openChangeWindowStrategy) {
    				if (old > now) {
    					for (; now < old ; now++) {
    						var tempZoom = Math.ceil(Math.sqrt(now+1));
    
    						me.videoStatus[now] && (me._windowList[tempZoom][now] = {
    													video: me.videoStatus[now].video,
    													id: me.videoStatus[now].id,
    													opts: me.videoStatus[now].opts,
    												},
    												me.close(now));
    					}
    						
    				} else {
    					while (oldZoom < nowZoom) {
    						oldZoom = oldZoom+1;
    						me._windowList[oldZoom] && $.each(me._windowList[oldZoom],function(index,obj) {
    							me.play(index, obj.video, obj.id, obj.opts);
    						});
    						me._windowList[oldZoom] = {};
    					}
    				}
    			} else {
    				if (old > now) {
    					for (; now < old ; now++) {
    						me.videoStatus[now] && me.close(now);
    					}
    				}
    			}
    		},*/

    /**
     * 切换分屏
     */
    _changeWindowsAction: function (num) {
      var me = this,
        old = me._opts.windows,
        now = num;
      //        		oldZoom = Math.sqrt(old),
      //        		nowZoom = Math.sqrt(now);
      if (old == now) {
        return;
      }
      if (me._opts.openChangeWindowStrategy) {
        if (old > now) {
          for (; now < old; now++) {
            //var tempZoom = Math.ceil(Math.sqrt(now+1));
            var tempZoom = me._getWindowsNum(now + 1);

            me.videoStatus[now] && (me._windowList[tempZoom][now] = {
                video: me.videoStatus[now].video,
                id: me.videoStatus[now].id,
                opts: me.videoStatus[now].opts,
              },
              me.close(now));
          }

        } else {
          while (old < now) {
            old = me._getNextWindowsNum(old);
            me._windowList[old] && $.each(me._windowList[old], function (index, obj) {
              me.play(index, obj.video, obj.id, obj.opts);
            });
            me._windowList[old] = {};
          }
        }
      } else {
        if (old > now) {
          for (; now < old; now++) {
            me.videoStatus[now] && me.close(now);
          }
        }
      }
    },

    /**
     * 获取当前的分屏数
     * now为当前窗口的编号
     */
    _getWindowsNum: function (now) {
      var me = this;
      var windowsArr = me._windowsArr;
      for (var index in windowsArr) {
        if (now <= windowsArr[index]) {
          return windowsArr[index];
        }
      }
    },

    /**
     * 获取下一窗口
     */
    _getNextWindowsNum: function (old) {
      var me = this;
      var windowsArr = me._windowsArr;
      for (var index in windowsArr) {
        if (index == windowsArr.length - 1) {
          return windowsArr[index]
        }
        if (old == windowsArr[index]) {
          return windowsArr[Number(index) + Number(1)];
        }
      }
    },

    _addStopHandler: function () {
      var me = this;
      window.stopVideo = function (playId, videoId) {
        me.close(me.getWindowByPlayId(playId));
        me.dispatch('streamoff');
      };
      me._regEvent('SCWebStopVideoEvent(playId,videoId)', 'stopVideo(playId,videoId);');

    },

    _addClickHandler: function () {
      var me = this;
      window.clickVideo = function (playId) {
        me.dispatch('click', me.videoStatus[me.getWindowByPlayId(playId)]);
      };
      me._regEvent('SCWebDecoderClick(playId,type)', 'clickVideo(playId);');
    },

    _addHishandler: function () {
      var me = this;
      window.playbackVideo = function (playId, videoId, historytime) {
        me.dispatch('playback', {
          playId: playId,
          videoId: videoId,
          historyTime: historytime
        });
      };
      me._regEvent('SCWebHistoryPlayTime(playId,videoId,historytime)', 'playbackVideo(playId,videoId,historytime);');
    },

    _regEvent: function (eventName, handlerName) {
      window._addScriptFlag = true;
      var script;
      try {
        script = $('<script>').attr({
          'for': this._opts.ocxName,
          'event': eventName,
        }).text('if (!_addScriptFlag) {' +
          handlerName +
          '}' +
          '_addScriptFlag = false;');

      } catch (e) {
        script = '<script for="' + this._opts.ocxName + '" event = "' + eventName + '" >' +
          'if (!_addScriptFlag) {' +
          handlerName +
          '}' +
          '_addScriptFlag = false;' +
          '</script>';
      }
      $('body').append(script);
    },

    _beforeUnload: function () {
      var me = this;
      window.onbeforeunload = function (e) {
        me.closeAll();
        me._obj.SCWebDecoderDestroy();
      };
    },

  }

  /**
   * 使用webRtc方式的video工具类
   */
  function VideoWebRtc($dom, opts) {
    if (!opts) {
      console.error('VideoWebRtc的参数opts不能为空');
      return;
    }
    this._init($dom, opts);
  }

  /**
   * 使用WEB-RTC方式的视频播放的方法
   */
  VideoWebRtc.prototype = {
    constructor: VideoWebRtc,

    VIDEO_DATA: [], //记录视频各分屏的状态

    /**
     * 播放视频
     * 参数：index(视频窗口编号，从0开始) video(视频设备id，即devId) id(标识，空的话使用设备id) opts(其他参数)
     * 返回true/false
     */
    play: function (index, video, id, opts) {
      var me = this;
      if (me.isPlaying(id) != -1) {
        console.info('该视频正在播放');
        return false;
      }
      // console.log("play >>> " + "video=" + video + "; id=" + id + "; index=" + index);
      me.dispatch('beforeplay', {
        index: index,
        video: video,
        id: id
      });

      if (index < 0) {
        console.error('index参数错误');
        return false;
      }
      if (!me.VIDEO_DATA.length) {
        me._initJanus(function () {
          me.VIDEO_DATA[index].play(video);

          opts = opts || {};

          if (me.VIDEO_DATA[index].playing) {
            me.VIDEO_DATA[index].opts = opts;
            me.VIDEO_DATA[index].id = id;
            me.dispatch('playsuccess', me.VIDEO_DATA[index]);
            return true;
          }
          return false;
        })
      } else {
        me.VIDEO_DATA[index].play(video);

        opts = opts || {};

        if (me.VIDEO_DATA[index].playing) {
          me.VIDEO_DATA[index].opts = opts;
          me.VIDEO_DATA[index].id = id;
          me.dispatch('playsuccess', me.VIDEO_DATA[index]);
          return true;
        }
        return false;
      }

      // document.getElementById("video-1").play(video)

    },

    /**
     * 在序号最小的空闲窗口播放视频
     * 参数：index(视频窗口编号，从0开始) video(视频设备id，即devId) opts(其他参数)
     * 返回true/false
     */
    playByOrder: function (video, id, opts) {
      var freeWindow = this._getMinIndexFreeWindow();

      if (freeWindow == -1) {
        return this.playInChoice(video, id, opts);
      }
      return this.play(freeWindow, video, id, opts);
    },

    /**
     * 扩展视频窗口数的播放方式
     */
    playByOrderExpandWindow: function (video, id, opts) {
      var me = this;

      var freeWindow = this._getMinIndexFreeWindow(0);

      //        	while (this._opts.windows < 16 && freeWindow == -1) {
      //         		me.setWindowsNum(me._getNextWindowsNum(parseInt(me._opts.windows)));
      //        		freeWindow = this._getMinIndexFreeWindow(0);
      //        	}

      while (freeWindow == -1) {
        var zoom = Math.sqrt(this._opts.windows * 1) + 1;

        if (this._opts.windows == 6) {
          this.setWindowsNum(9);
        } else {
          this.setWindowsNum(Math.pow(zoom, 2));
        }

        freeWindow = this._getMinIndexFreeWindow(zoom - 1);
      }

      if (this._getChoiceWindow() == -1 && this._getMinIndexFreeWindow() != -1) {
        this.setChoiceWindow(this._getMinIndexFreeWindow());
      }

      if (freeWindow == -1 ||
        (this._getChoiceWindow() != -1 && !this.getInChoiceVideo() && this._opts.windowsNum > 1)) {
        return this.playInChoice(video, id, opts);
      }

      return this.play(freeWindow, video, id, opts);
    },

    /**
     * 播放所有视频
     */
    playAll: function (array) {
      if (array.length > this._opts.windows) {
        throw new Error('windows is not enough');
      }
      var me = this;
      me.closeAll();
      $.each(array, function (i, obj) {
        me.play(i, obj.video, obj.id, obj.opts);
      });
    },

    /**
     * 在鼠标选中的窗口中播放视频
     */
    playInChoice: function (video, id, opts) {
      var me = this;
      var selView = $('[video-flag="' + me._opts.windowsBeginIndex + '"]>li.sel');
      if (selView.length) {
        if (me.VIDEO_DATA[selView.index()].playing) {
          me.close(selView.index());
          //延时打开  禁止同时一关一开
          setTimeout(function () {
            me.play(selView.index(), video, id, opts);
          }, 1000);
        } else {
          me.play(selView.index(), video, id, opts);
        }
      }
    },

    /** 
     * 检索当前点的视频是否被播放，被播放则返回播放的视频窗口
     */
    isPlaying: function (id) {
      var me = this;
      var index = -1;
      $.each(me.VIDEO_DATA, function (key, val) {
        if (id == val.id && me.VIDEO_DATA[key].playing) {
          index = key;
        }
      });
      return index;
    },

    /**
     * 关闭指定窗口的视频
     */
    close: function (index, isSave) {
      if (index < 0) {
        console.info('index参数错误');
        return;
      }

      this.VIDEO_DATA[index].close();

      if (!isSave) {
        this.dispatch('afterclose', this.VIDEO_DATA[index]);
      }

    },

    /**
     * 关闭所有视频
     */
    closeAll: function (isSave) {
      var me = this;

      var openVideos = [];
      for (var i = me._opts.windowsBeginIndex; i < me._opts.windowsBeginIndex + me._opts.windowsNum; i++) {
        if (me.VIDEO_DATA[i].playing) {
          me.close(i, isSave)
        }
      }

      //			if(!openVideos.length) return;
      //			
      //			//适当延时进行关闭
      //			var count = 0;			
      //			var interval = setInterval(function(){
      //				if(count == openVideos.length){
      //					clearInterval(interval);
      //				}else{
      //					me.close(openVideos[count], isSave)
      //					count++;
      //				}
      //			}, 50);
    },

    /**
     * 设置鼠标选中窗口
     */
    setChoiceWindow: function (index) {
      $('.screen-' + (index + 1)).click();
    },

    /**
     * 获取视频窗口数
     */
    getWindowsNum: function () {
      return this._opts.windows;
    },

    /**
     * 分屏切换，传入的参数为新的屏数
     */
    setWindowsNum: function (num) {
      var me = this;

      //切换屏幕后 选中空闲最小的窗口
      if (me._opts.windows != num && me._getMinIndexFreeWindow() != -1) {
        me.setChoiceWindow(me._getMinIndexFreeWindow());
      }

      $('[video-flag="' + me._opts.windowsBeginIndex + '"]').removeClass("mode-" + me._opts.windows).addClass("mode-" + num);
      var _li = $('[video-flag="' + me._opts.windowsBeginIndex + '"]>li').hide();
      me._opts.windows = num;
      for (var i = 0; i < num; i++) {
        _li.eq(i).show();
      }
      //分屏切换事件
      this.dispatch('screenchange', {
        windowNums: num
      });
    },

    /**
     * 询问是否无可用窗口
     */
    isUnavailable: function () {
      return this._opts.windows == 16 && this._getMinIndexFreeWindow() == -1;
    },

    /**
     * 执行轮巡
     */
    startPoll: function (array, time) {
      if (!array || array.length == 0) {
        promptAlarm('请选择视频设备！');
        return false;
      }

      time = $.isNumeric(time) ? time : this._opts.pollInterval;
      this._pollArray = array;
      var me = this,
        windowNum = me._opts.windows,
        maxNum = array.length,
        nowNum = 0;
      me.saveList();

      this._polltimer = new PollTimer(function (firstRun) {
        me.closeAll();
        for (var i = 0; i < windowNum; i++) {
          if (nowNum == maxNum) {
            nowNum = 0;
            if (maxNum < windowNum) {
              break;
            }
          }

          me.playByOrder(array[nowNum].video, array[nowNum].id, array[nowNum].opts);
          nowNum++;
        }
        if (firstRun) {
          me.dispatch('startpoll', array);
        }
      }, time);
    },

    /**
     * 结束轮巡
     */
    stopPoll: function () {
      if (!this._polltimer) {
        return;
      }

      this._polltimer.stop();
      this._polltimer = undefined;

      console.log('------> 轮巡结束 <-------');
      this.dispatch('stoppoll', {});

      this._pollArray = null;
      this.closeAll();
      //恢复之前打开的视频
      //this.playSaveList();
    },

    /**
     * 获取是否在轮巡
     */
    isPolling: function () {
      return !!this._polltimer;
    },

    holder: function (type, opts, isStop) {
      var index = this._getChoiceWindow();
      if (index < 0) {
        promptFailed('请先选中视频');
        return false;
      }
      return this.VIDEO_DATA[index].holder(type, opts, isStop);
    },

    /**
     * 视频回放
     * @param startTime [YYYY-MM-DDTHH:mm:ss]
     * @param endTime
     * @return playId
     */
    playHistory: function (video, startTime, endTime, opts) {
      var me = this;

      var index;
      //回放是一分屏的默认使用一个窗口
      if (me._opts.windowsNum == 1) {
        index = me._opts.windowsBeginIndex;
      } else {
        index = me._getMinIndexFreeWindow();
      }

      if (index < 0) {
        console.error('窗口编号获取失败！')
      }

      me.VIDEO_DATA[index].opts = opts;
      return me.VIDEO_DATA[index].playback(video, startTime, endTime);
    },

    /**
     * 关闭历史流
     */
    closeHistory: function (index) {
      var me = this;

      if (!index) {
        var index;
        if (me._opts.windowsNum == 1) {
          index = me._opts.windowsBeginIndex;
        }
      }

      return me.VIDEO_DATA[index].close("stop");
    },

    /**
     * 历史流控制
     * @param  {number} video    
     * @param  {string} playType  播放类型（play && pause & stop）
     * @param  {numner} playSpeed 播放速率
     * @param  {string} startTime 回放时间（暂时无用）
     */
    historyControl: function (video, playType, playSpeed, startTime) {
      var me = this;
      var index;
      if (me._opts.windowsNum == 1) {
        index = me._opts.windowsBeginIndex;
      } else {
        index = me._getChoiceWindow();
      }
      return me.VIDEO_DATA[index].playbackControl(video, playType, playSpeed, startTime);
    },

    saveList: function () {
      this._saveList = cloneObj(this.VIDEO_DATA);
    },


    playSaveList: function () {
      if (!this._saveList) {
        return;
      }
      this.closeAll();
      var me = this;
      $.each(this._saveList, function (index, obj) {
        if (obj.video) {
          me.play(obj.index, obj.video, obj.id, obj.opts);
        }
      });
    },

    /**
     * 获取当前选择窗口的视频video
     */
    getInChoiceVideo: function () {
      var me = this;
      var selView = $('[video-flag="' + me._opts.windowsBeginIndex + '"]>li.sel');
      if (selView.length && me.VIDEO_DATA.length > 0 && me.VIDEO_DATA[selView.index()].video) {
        return me.VIDEO_DATA[selView.index()];
      }
      return undefined;
    },

    /**
     * 设置全屏
     */
    setFullScreen: function () {
      this._fullScreenEvent(document.getElementById("video-main-web-rtc"));
    },
    /**
     * 获取当前视频控件的配置项
     */
    getVideoControllerOpts: function () {
      return this._opts;
    },

    /**
     * 添加事件
     */
    addListener: function (type, handler, key) {
      videoListener.addListener(type, handler, key);
    },

    /**
     * 删除事件
     */
    removeListener: function (type, handler) {
      videoListener.removeListener(type, handler);
    },
    /**
     * 派发事件
     */
    dispatch: function (e, options) {
      videoListener.dispatch(e, options);
    },

    /**
     * 获取编号最小的空闲窗口的编号
     */
    _getMinIndexFreeWindow: function (index) {
      var me = this;
      index = index || me._opts.windowsBeginIndex;
      for (; index < me._opts.windowsBeginIndex + me._opts.windows; index++) {
        if (this.videoStatus && this.videoStatus.length > 0) {

        } else {
          return 0;
        }
        if (this.videoStatus && this.videoStatus.length > 0 && !me.VIDEO_DATA[index].playing) {
          return index;
        }
      }
      return -1;
    },

    /**
     * 获取选中的窗口的index
     */
    _getChoiceWindow: function () {
      var me = this;
      var selView = $('[video-flag="' + me._opts.windowsBeginIndex + '"]>li.sel');
      if (selView.length) {
        return selView.index();
      }
      return -1;
    },

    /**
     * 获取下一窗口
     */
    _getNextWindowsNum: function (old) {
      var me = this;
      var windowsArr = me._windowsArr;
      for (var index in windowsArr) {
        if (index == windowsArr.length - 1) {
          return windowsArr[index]
        }
        if (old == windowsArr[index]) {
          return windowsArr[Number(index) + Number(1)];
        }
      }
    },

    /**
     * 设置鼠标选中窗口
     */
    _clickWindow: function () {
      var me = this;
      //视频窗口选中
      $('[video-flag="' + me._opts.windowsBeginIndex + '"]>li').click(function () {
        $('[video-flag="' + me._opts.windowsBeginIndex + '"]>li').removeClass("sel");
        $(this).addClass("sel");

        //如果视频正在播放则分发点击消息
        if (me.getInChoiceVideo()) {
          me.dispatch('click', me.getInChoiceVideo());
        }
      });
    },

    /*
	 * 总的初始化
	 * 参数示例：			
	 * var opts = {
				windows: 4,   //初始化的窗口数
				conf: {       //配置参数
					user: 'admin',   //用户名
					passwd: '6b86b273ff34fce19d6b804eff5a3f5747ada4eaa22f1d49c01e52ddb7875b4b', //密码
					janusUrl: 'wss:  //192.168.103.226:8989', //janusServer服务地址
				},
				pollInterval: 30     //轮巡时间，单位秒
		};
	 */
    _init: function ($dom, opts) {
      this.VIDEO_DATA = [];
      var me = this;
      //配置项
      me._opts = {
        windows: 4,
        conf: {},
        pollInterval: 10,
        windowsNum: 16
      };

      $.extend(me._opts, opts);

      var windowsArr = me._opts.windowsArr;
      if (!windowsArr || windowsArr.length == 0) {
        me._windowList = {
          1: {},
          4: {},
          6: {},
          9: {},
          16: {}
        }
        me._windowsArr = [1, 4, 6, 9, 16];
      } else {
        me._windowList = {};
        for (var index in windowsArr) {
          var item = windowsArr[index];
          me._windowList[item] = {};
        }
        me._windowsArr = windowsArr;
      }

      //获取起始的窗口位置
      me._opts.windowsBeginIndex = windowsSum;
      //窗口总数
      windowsSum += me._opts.windowsNum;

      //初始化界面
      me._initView($dom);
      //初始化Janus
      // me._initJanus();
      //初始化按钮点击事件
      me._initBtnEvent();

      //设置鼠标点击选中窗口
      me._clickWindow();
      //显示视频信息：名称、分辨率、码率、丢包率
      me._showVideoInfo();
      //双击某个视频全屏
      me._dbClickFullScreen();
    },

    /**
     * 初始化按钮点击事件
     */
    _initBtnEvent: function () {
      var me = this;
      //接收音频事件
      $("button[name='recvAudio']").click(function () {
        var index = Number($(this).parent().parent().attr("index"));

        if (!me.VIDEO_DATA[index].playing) {
          promptAlarm('请选择播放的视频源！');
          return;
        }

        if ($(this).attr('class') == 'recv-audio-btn') {
          //发送停止播放音频的请求
          me.VIDEO_DATA[Number(index)].operateAudio("stop_audio")
          $(this).attr('class', 'unrecv-audio-btn');
          me.VIDEO_DATA[Number(index)].videoBox.muted = false;
        } else {
          //发送播放音频的请求
          me.VIDEO_DATA[Number(index)].operateAudio("recv_audio");
          $(this).attr('class', 'recv-audio-btn');
          me.VIDEO_DATA[Number(index)].videoBox.muted = true;
        }
      });

      //发送音频事件
      //        	$("button[name='sendAudio']").click(function(){
      //        		var index = Number($(this).parent().parent().attr("index"));
      //        		
      //        		if (!me.VIDEO_DATA[index].playing) {
      //        			promptAlarm('请选择播放的视频源！');
      //        			return;
      //        		}
      //        		
      //        		if ($(this).attr('class') == 'send-audio-btn') {
      //        			//发送停止发送音频的请求
      //        			me.VIDEO_DATA[Number(index)].operateAudio("unsend_audio")    
      //        			$(this).attr('class', 'unsend-audio-btn');
      //        		} else {         			
      //        			//发送播放音频的请求
      //        			me.VIDEO_DATA[Number(index)].operateAudio("send_audio")  
      //        			$(this).attr('class', 'send-audio-btn');
      //        		}      		
      //        	});
    },

    /**
     * 双击某个视频全屏
     */
    _dbClickFullScreen: function () {
      var me = this;
      $('[video-flag="' + me._opts.windowsBeginIndex + '"]').find('.video-box').on("dblclick", function () {
        if (!$('#overlayb').attr('dbl')) {
          $('#overlayb').addClass('videoDblPar').attr('dbl', true);
          $('#overlayb').css({
            width: '1000px',
            height: '600px',
            top: '80px'
          })
          $('#overlayb ul').css({
            padding: '19px',
            boxSizing: 'border-box',
            marginTop: '0px'
          })
        } else {
          $('#overlayb').removeClass('videoDblPar').attr('dbl', '');
          $('#overlayb').css({
            width: '310px',
            height: '180px',
            top: '94px'
          })
          $('#overlayb ul').css({
            padding: 'revert',
            boxSizing: 'unset',
            marginTop: 'revert'
          })
        }
      });
    },

    /**
     * 全屏事件
     */
    _fullScreenEvent: function (el) {
      var isFullscreen = el.fullScreen || el.mozFullScreen || el.webkitIsFullScreen;
      if (!isFullscreen) { //进入全屏,多重短路表达式
        (el.requestFullscreen && el.requestFullscreen()) ||
        (el.mozRequestFullScreen && el.mozRequestFullScreen()) ||
        (el.webkitRequestFullscreen && el.webkitRequestFullscreen()) || (el.msRequestFullscreen && el.msRequestFullscreen());
      }

      //关闭全屏
      //        	colseFullscreen();        	
      //        	function colseFullscreen() {
      //	        	el.onmouseup = function(e){     //在body里点击触发事件
      //	                if(e.button === 0){       
      //	                	document.exitFullscreen?document.exitFullscreen():
      //	                	document.mozCancelFullScreen?document.mozCancelFullScreen():
      //	                	document.webkitExitFullscreen?document.webkitExitFullscreen():'';	                	
      //	                }
      //	            }
      //        	}
    },

    /**
     * 在视频界面上显示视频的信息 码率、分辨率、丢包率
     */
    _showVideoInfo: function () {
      var me = this;

      function clock() {
        // for (var i = 0; i < me.VIDEO_DATA.length; i++) {
        //   if (me.VIDEO_DATA[i].playing) {
        //     var number = me._opts.windowsNum;
        //     var videoObj = document.getElementById('video-' + number);

        //     var width = videoObj.videoWidth;
        //     var height = videoObj.videoHeight;

        //     //码率     
        //     var bitrate = me.VIDEO_DATA[i].sipcall.getBitrate();
        //     if (width == 0 || !bitrate || bitrate.indexOf("kbits") == -1) {
        //       continue;
        //     }

        //     var config = me.VIDEO_DATA[i].sipcall.webrtcStuff;
        //     me._setPacketsLostRate(i, config, me);

        //     var videoInfoObj = document.getElementById('info-' + number);
        //     var videoName = me.VIDEO_DATA[i].opts && me.VIDEO_DATA[i].opts.name ?
        //       me.VIDEO_DATA[i].opts.name : me.VIDEO_DATA[i].video;
        //     videoInfoObj.innerHTML = videoName + '&nbsp;&nbsp;' + width + "×" + height +
        //       '<br>' + bitrate + '&nbsp;&nbsp;Lost：' + me.VIDEO_DATA[i].packetsLostRate;
        //   }
        // }
      }
      var timer = setInterval(clock, 1000);
    },
    /**
     * 获取设置丢包率
     */
    _setPacketsLostRate: function (index, config, me) {
      if (config.pc != null && config.pc != undefined && config.pc.getStats) {
        config.pc.getStats().then(function (stats) {
          stats.forEach(function (res) {
            if (!res) {
              return;
            }
            var inStats = false;
            // Check if these are statistics on incoming media
            if ((res.mediaType === "video" || res.id.toLowerCase().indexOf("video") > -1) &&
              res.type === "inbound-rtp" && res.id.indexOf("rtcp") < 0) {
              // New stats
              inStats = true;
            } else if (res.type == 'ssrc' && res.bytesReceived &&
              (res.googCodecName === "VP8" || res.googCodecName === "")) {
              // Older Chromer versions
              inStats = true;
            }
            // Parse stats now
            if (inStats) {
              if (res.hasOwnProperty("packetsLost")) {
                //console.info('丢包率：' + res.packetsLost);
                if (!res.packetsLost || isNaN(res.packetsLost) || Number(res.packetsLost) == '0') {
                  me.VIDEO_DATA[index].packetsLostRate = 0;
                } else {
                  var packetsLost = Number(res.packetsLost) - Number(me.VIDEO_DATA[index].packetsLostSum);
                  var packetsReceived = Number(res.packetsReceived) - Number(me.VIDEO_DATA[index].packetsReceivedSum);

                  me.VIDEO_DATA[index].packetsLostSum = res.packetsLost;
                  me.VIDEO_DATA[index].packetsReceivedSum = res.packetsReceived;
                  var packetsLostRate = (Number(packetsLost) / (Number(packetsLost) + Number(packetsReceived))) * 100;
                  me.VIDEO_DATA[index].packetsLostRate = packetsLostRate.toFixed(2) + '%';
                }
                //window.VIDEO_DATA[index].packetsLostRate = (Number(res.packetsLost) / (Number(res.packetsLost) + Number(res.packetsReceived))) * 100;
                /*   					               		videoInfoObj.innerHTML = videoName + '&nbsp;&nbsp;' + width + "×" + height +
                								'<br>' + bitrate + '&nbsp;&nbsp;Lost：' + res.packetsLost;*/
              }
            }

          });
        });
      }
    },

    /**
     * 界面的初始化，在传过来的dom中创建界面
     */
    _initView: function ($dom) {
      var me = this;
      var objClass = (me._opts.windowsNum == 1 ? 'video-main-full mode-' : 'video-main mode-') + me._opts.windows;
      var videoHtml = '<ul class="' + objClass + '" id="video-main-web-rtc" video-flag="' + me._opts.windowsBeginIndex + '">';
      var index = me._opts.windowsBeginIndex + 1;
      for (var i = index; i < index + me._opts.windowsNum; i++) {
        videoHtml += '<li class="screen-' + i + '" index="' + (i - 1) + '"><video muted class="video-box" id="video-' + me._opts.windowsNum + '" autoplay ></video>' +
          '<div class="info hide" id="info-' + i + '"></div>' +
          '<div class="audio hide">';
        !checkIsHttp() && (videoHtml += '<button type="button" class="unsend-audio-btn" name="sendAudio"></button>');
        videoHtml += '<button type="button" class="unrecv-audio-btn" name="recvAudio"></button>' +
          '</div>' +
          '</li>';
      }
      videoHtml += '</ul>';
      $dom.append(videoHtml);

      me.setWindowsNum(me._opts.windows);
    },

    /**
     * Janus的初始化
     */
    _initJanus: function (cb) {
      var me = this;

      //        	if (window.parent && window.parent.janus) {
      //        		me._initSVideo(window.parent.janus);
      //        		return;
      //        	}

      Janus.init({
        debug: "error",
        callback: function () {
          if (!Janus.isWebrtcSupported()) {
            alert("不支持WEB-RTC");
            return;
          }
          var janus = new Janus({
            server: me._opts.conf.janusUrl,
            success: function () {
              // console.log("janusServer连接成功");
              me._initSVideo(janus, cb);
            },
            error: function (error) {
              // alert('连接失败：'+ error);
            },
            destroyed: function () {

            }
          });

        }
      });
    },
    /**
     * 初始化插件、登陆，初始化窗口
     */
    _initSVideo: function (janus, cb) {
      var me = this;

      //已经初始化过，则直接拿来用
      //   if (janus && (registered || (window.parent && window.parent.registered))) {
      //     //生成主界面
      //     for (var i = me._opts.windowsBeginIndex; i < me._opts.windowsBeginIndex + me._opts.windowsNum; i++) {
      //       me.VIDEO_DATA[i] = new SVideo({
      //         index: i,
      //         janus: janus

      //       },cb);
      //     }
      //     return;
      //   }

      //初始化一个插件，用来登陆，不能用此插件播放视频。
      var _loginSipCall = null;
      janus.attach({
        plugin: "janus.plugin.videoserver",
        opaqueId: "siptest-" + Janus.randomString(12),
        success: function (pluginHandle) {
          // console.log("janus登陆插件初始化成功");					
          _loginSipCall = pluginHandle;
          var register = {
            "request": "register",
            "username": me._opts.conf.user,
            "secret": me._opts.conf.passwd,
          };
          _loginSipCall.send({
            "message": register
          });
        },
        error: function (error) {
          console.error("janus登陆插件初始化失败");
        },
        onmessage: function (msg, jsep) {
          if (msg.error_code) {
            console.error(msg.error)
            promptFailed(FAILED_CODE[msg.error_code] || '错误码：' + msg.error_code);
            return false;
          }

          var result = msg["result"];
          var event = result["event"];

          if (result.error_code && result.error_code != 0) {
            promptFailed(FAILED_CODE[result.error_code] || '错误码：' + result.error_code);
          }

          if (result !== null && result !== undefined && result["event"] !== undefined && result["event"] !== null) {
            // console.log("result event:" + event);
            if (event === 'registration_failed') {
              promptFailed("janus登陆失败: " + result["code"] + " " + result["reason"]);
              return;
            }
            if (event === 'registered') {
              userToken = result["userToken"];
              // console.log('janus登陆成功')
              registered = true;

              //生成主界面
              me.VIDEO_DATA[0] = new SVideo({
                index: 0,
                janus: janus

              }, cb);
              //   for (var i = me._opts.windowsBeginIndex; i < me._opts.windowsBeginIndex + me._opts.windowsNum; i++) {
              //     me.VIDEO_DATA[i] = new SVideo({
              //       index: i,
              //       janus: janus

              //     },cb);
              //   }
            }
          }


          window.onunload = function () {
            videoController.closeAll();
          }
        }
      });
    },

  }

  var FAILED_CODE = {
    1001: "账号或密码错误",
    1002: "该帐号已连接",
    1004: "没有鉴权",
    2001: "未携带token或token错误",
    2002: "视频源id不存在",
    2003: "操作指令非法(该账号不允许执行这个指令，或者不支持该指令)",
    3001: "nat通道未建立",
    3002: "该视频流已在传输",
    3003: "无法获取远端视频流",
    4001: "视频流断开连接",
    4002: "获取视频失败",
    5000: "内部错误",
    8001: "设备不支持该指令",
    453: "videoServer连接失败",
    454: "录像回放窗口已占用，请先停止播放",
    455: "无视频录像，操作失败"
  }
  //window.VIDEO_DATA = [];//记录视频各分屏的状态
  window.windowsSum = 0; //当前页面的视频总数，可能有多个VideoWebRtc对象
  var userToken = null;
  var registered = false;

  function SVideo(opts, cb) {
    this.janus = opts.janus;
    this.sipcall = null;
    this.index = opts.index;
    this.videoBox = $('#video-' + (this.index + 1));
    this.init(cb);
  }

  /**
   * 使用web-rtc方式的视频播放
   */
  SVideo.prototype = {

    /**
     * 初始化
     */
    init: function (cb) {
      var self = this;

      self.janus.attach({
        plugin: "janus.plugin.videoserver",
        opaqueId: "siptest-" + Janus.randomString(12),

        success: function (pluginHandle) {
          self.sipcall = pluginHandle;
          var delayTime = Math.random();
          cb()
          //setScreenNum(1); //设置一分屏
          //   if (!!devicedId) {
          //     autoPlayVideo(devicedId);
          //   } else {
          //     console.log("设备号未输入!即将播放测试数据");
          //     autoPlayVideo("31010112001328036008");
          //   }
        },

        error: function (error) {
          console.error("插件初始化失败");
        },

        consentDialog: function (on) {
          console.log("Consent dialog should be " + (on ? "on" : "off") + " now");
        },

        onmessage: function (msg, jsep) {
          if (!registered) {
            promptFailed("请先登陆");
          }

          if (msg.error_code) {
            console.error(msg.error)
            promptFailed(FAILED_CODE[msg.error_code] || '错误码：' + msg.error_code);
            return false;
          }

          var result = msg["result"];
          var event = result["event"];

          if (result.error_code && result.error_code != 0) {
            videoListener.dispatch('afterclose', self);

            //播放失败
            self.sipcall.hangup(); //插件挂断
            self.videoBox.hide(); //视频窗video标签隐藏
            self.playing = false; //缓存数据-是否播放视频置否
            self.video = null; //缓存数据-视频video置空
            self.packetsLostRate = 0; //丢包率 每秒刷新
            self.packetsLostSum = 0; //丢包数
            self.packetsReceivedSum = 0; //接收数

            //隐藏视频信息
            self.videoBox.parent().find('.info').hide();
            //隐藏音频喇叭
            self.videoBox.parent().find('.audio').hide();
            self.videoBox.parent().removeClass("loading").find(".stream-loading").remove(); //移除loading标签

            promptFailed(FAILED_CODE[result.error_code] || '错误码：' + result.error_code);
          }

          switch (event) {
            //即将播放视频 
            case 'incomingcall':
              self.sipcall.createAnswer({
                jsep: jsep,
                media: {
                  audioSend: !checkIsHttp(),
                  videoSend: false,
                  audioRecv: true,
                  videoRecv: true
                },
                success: function (jsep) {
                  var body = {
                    request: "accept",
                    videoidentify: result["videoidentify"],
                    playseq: parseInt(result["playseq"])
                  };
                  self.sipcall.send({
                    "message": body,
                    "jsep": jsep
                  });
                },
                error: function (error) {
                  console.error(error);
                  var body = {
                    "request": "decline",
                    "code": 480
                  };
                  self.sipcall.send({
                    "message": body
                  });
                }
              });
              break;
              //呼叫失败  
            case 'callfaild':
              //promptFailed(FAILED_CODE[result.error_code] || '错误码：' + result.error_code);
              break;
              //云台    
            case 'ptz':
              break;
              //历史流控制	
            case 'av_control':
              break;
            default:
              // console.log('event：' + event);
              break;
          }
        },

        onremotestream: function (stream) {
          // console.log('onremotestream：分屏=' + (self.index + 1) + ', video='  + self.video);				
          Janus.attachMediaStream(self.videoBox.get(0), stream);
        },

        onlocalstream: function (stream) {
          //Janus.attachMediaStream(self.videoBox.get(0), stream);

          //var s = stream.getAudioTracks()[0];
          //stream.removeTrack(s);    					
          //    					self.sipcall.webrtcStuff.myStream.addTrack(s);  					
          //    					self.sipcall.webrtcStuff.myStream.removeTrack(s);

          var btnObj = self.videoBox.parent().find("button[name='sendAudio']");
          btnObj.unbind('click');
          stream.getAudioTracks()[0].enabled = false;

          btnObj.click(function () {
            if (btnObj.attr('class') == 'send-audio-btn') {
              stream.getAudioTracks()[0].enabled = false;
              self.operateAudio("unsend_audio");
              btnObj.attr('class', 'unsend-audio-btn');
            } else {
              stream.getAudioTracks()[0].enabled = true;
              self.operateAudio("send_audio");
              btnObj.attr('class', 'send-audio-btn');
            }
          });
          //stream.getTracks().forEach(track => track.stop());
          // console.log('onrelocalstream：分屏=' + (self.index + 1) + ', video='  + self.video);
        },

        oncleanup: function () {
          // console.log('oncleanup：分屏=' + (self.index + 1));			
        }
      });

      //<video>注册playing/canplay事件，用于判断视频播放成功
      self.videoBox.bind("canplay play playing", function () {
        if (self.video) {
          if (self.videoBox.is(':visible')) return;

          console.log('分屏=' + (self.index + 1) + ', ' + self.video + ' 播放成功');
          //promptSuccess('分屏' + (self.index + 1) + ' 播放成功');
          self.videoBox.show();
          self.videoBox.parent().removeClass("loading").find(".stream-loading").remove();

          //显示视频信息
          // if (Global != undefined && Global.showInfoDisenable) {
          // 	self.videoBox.parent().find('.info').hide();
          // }
          // else {
          // 	self.videoBox.parent().find('.info').show();
          // }
          //显示音频按钮
          /*
          self.videoBox.parent().find('.audio').show();
          self.videoBox.parent().find('.recv-audio-btn').attr("class", "unrecv-audio-btn");
          self.videoBox.parent().find('.send-audio-btn').attr("class", "unsend-audio-btn");
          */
        }
      });
    },

    /**
     * 播放视频
     * video：视频编号（ID）
     */
    play: function (video) {
      if (!video) {
        //alert("请输入视频ID");
        promptAlarm('视频ID不能为空');
        return;
      }
      var body = {
        request: "call",
        videoidentify: video,
        playseq: this.index,
        userToken: userToken,
        autoack: true
      };
      this.sipcall.send({
        "message": body
      });
      this.video = video;
      this.playing = true;
      this.packetsLostRate = 0;
      this.packetsLostSum = 0;
      this.packetsReceivedSum = 0;

      //loading
      var _li = this.videoBox.parent();
      if (!_li.hasClass("loading")) {
        _li.addClass("loading").append('<div class="stream-loading"><span class="iconfont icon-jiankong1"></span></div>');
      }
      // console.log("视频播放：分屏=" + (this.index + 1) + ",设备ID=" + video);
    },

    close: function (type) {
      var reqType = type ? type : "hangup";
      if (!this.playing) return;
      var _hangup = {
        "request": reqType,
        "videoidentify": this.video,
        "playseq": this.index,
        "token": userToken
      };
      this.sipcall.send({
        "message": _hangup
      });
      this.sipcall.hangup();
      this.videoBox.hide();
      this.playing = false;
      this.video = null;
      this.packetsLostRate = 0;
      this.packetsLostSum = 0;
      this.packetsReceivedSum = 0;
      //清除显示的视频信息
      document.getElementById('info-' + (Number(this.index) + Number(1))).innerHTML = '';
      //隐藏视频信息
      this.videoBox.parent().find('.info').hide();
      //隐藏音频喇叭
      this.videoBox.parent().find('.audio').hide();
      //避免没收到成功时就点击关闭，清除loading框
      this.videoBox.parent().removeClass("loading").find(".stream-loading").remove();
    },

    /**
     * 云台控制
     * up  				上
     * down				下
     * left				左
     * right			右
     * upleft			上左
     * upright			上右
     * downleft			下左
     * downright		下右
     * zoomin			倍率变大
     * zoomout			倍率变下
     * focusnear		焦点+
     * focusfar			焦点-
     * irisopen			光圈+
     * irisclose		光圈-
     * pointset			设置预置点
     * pointdel			删除预置点
     * pointgoto		到预置点
     * scansetleft		自动扫描左边界
     * scansetright		自动扫描又边界
     * scansetspeed		设置扫描速度
     * scanrun			自动扫描运行
     * cruiseadd		添加巡航点
     * cruisedel		删除巡航点
     * cruisespeed		设置巡航点速度
     * cruisepausetime	设置巡航滞留时间
     * cruiserun		启动巡航
     */
    holder: function (type, opts, isStop) {
      if (!this.video || !this.playing) {
        //alert("请输入视频ID");
        promptAlarm('未选中播放的视频！');
        return;
      }

      var holdType = 'up down left right upleft upright downleft downright zoomin zoomout focusnear focusfar irisopen irisclose pointset pointdel pointgoto ' +
        'scansetleft scansetright scansetspeed scanrun cruiseadd cruisedel cruisespeed cruisepausetime cruiserun';
      var typeVal = (Number(holdType.split(' ').indexOf(type)) + Number(1));

      console.log("holdType：" + typeVal + " type：" + type + (isStop ? ' 停止' : ''));

      if (!typeVal || typeVal <= 0) {
        console.error('异常PTZ指令：' + typeVal);
        return false;
      }

      var body = {
        request: "ptz",
        videoidentify: this.video,
        playseq: this.index,
        userToken: userToken,
      };

      body.cmd = {
        speed: opts.speed ? opts.speed : 200,
        group: 0,
        present: opts.present ? opts.present : 0,
        time: 0,
        type: typeVal
      }

      if (isStop) {
        console.log(">>>>yuntai control,stop, video=" + this.video);
        body.cmd.action = 1;
      } else {
        body.cmd.action = 0;
        console.log('设备号：' + this.video + ', 云台移动-->' + type);
      }

      this.sipcall.send({
        "message": body
      });
    },

    /**
     * 历史回放
     * video设备ID startTime录像开始 stopTime录像结束 例：2015-07-22T12:00:00，注意T隔开
     */
    playback: function (video, startTime, stopTime) {
      if (!video) {
        //alert("请输入视频ID");
        promptAlarm('视频ID不能为空');
        return;
      }

      var body = {
        request: "av_playback",
        videoidentify: video,
        playseq: this.index,
        userToken: userToken,
        start_time: startTime,
        stop_time: stopTime
      };

      console.log(">>>>playback video=" + video + " startTime=" + startTime + " stopTime=" + stopTime);
      this.sipcall.send({
        "message": body
      });
      this.video = video;
      this.playing = true;
      this.packetsLostRate = 0;
      this.packetsLostSum = 0;
      this.packetsReceivedSum = 0;

      //loading
      var _li = this.videoBox.parent();
      if (!_li.hasClass("loading")) {
        _li.addClass("loading").append('<div class="stream-loading">等待数据流传送...</div>');
      }
      console.log("历史回放：分屏=" + (this.index + 1) + ",视频ID=" + video);
    },

    /**
     * 历史回放控制
     * video设备ID playType类型 playSpeed速率 startTime开始时间
     */
    playbackControl: function (video, playType, playSpeed, startTime) {
      var self = this;

      var body = {
        request: "av_control",
        videoidentify: video,
        playseq: self.index,
        userToken: userToken,
        start_time: startTime,
        rate: String(playSpeed),
        cmd: playType
      };

      console.log(">>>>playbackControl video=" + video + " playType=" + playType + " playSpeed=" + playSpeed);

      //setTimeout(function (){
      self.sipcall.send({
        "message": body
      });
      //}, 1000);

      if (playType == 'stop') {
        self.videoBox.hide();
        self.playing = false;
        self.video = null;
        self.packetsLostRate = 0;
        self.packetsLostSum = 0;
        self.packetsReceivedSum = 0;
        //清除显示的视频信息
        document.getElementById('info-' + (Number(self.index) + Number(1))).innerHTML = '';
        //避免没收到成功时就点击关闭，清除loading框
        self.videoBox.parent().removeClass("loading").find(".stream-loading").remove();
      }
    },

    /**
     * 音频流操作
     * requstType: recv_audio、stop_audio、send_audio、unsend_audio
     */
    operateAudio: function (requestType) {
      var self = this;

      if (!self.video) {
        //alert("请输入视频ID");
        promptAlarm('视频ID不能为空');
        return;
      }
      var body = {
        request: requestType,
        videoidentify: self.video,
        playseq: self.index,
        userToken: userToken,
      };
      self.sipcall.send({
        "message": body
      });

      console.log("音频操作=" + requestType + ", 分屏=" + (self.index + 1) + ",设备ID=" + self.video);
    }
  }

  return isIE() ? VideoOcx : VideoWebRtc;
}));
